package znet

import (
	"errors"
	"fmt"
	"log"
	"net"
	"time"
	"zinxp/utils"
	"zinxp/ziface"
)

//iServer的接口实现,定义Server服务类
type Server struct {
	Name      string
	IPVersion string
	IP        string
	Port      int
	//当前Server的消息管理模块，用来绑定MsgId和对应的处理方法
	msgHandler ziface.ImsgHandle
	//当前Server的连接管理器
	ConnMgr ziface.IConnManager

	OnConnStart func(conn ziface.IConnection)
	OnConnStop func(conn ziface.IConnection)
}

/*
CallBackToClient是我们给当前客户端conn对象绑定的handle方法，当然目前是server端强制绑定的回显业务，
    我们之后会丰富框架，让这个用户可以让用户自定义指定handle。
*/
//============== 定义当前客户端链接的handle api ===========
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	//回写
	log.Println("[Conn Handle] CallBackToClient ...")
	n, err := conn.Write(data[:cnt])
	if err != nil {
		log.Println("write back buf error ", err)
		return errors.New("CallBackToClient error")
	}
	if n != cnt {
		log.Printf("can not write %d to the client\n", cnt)
		return errors.New("CallBackToClient can't write enough")
	}
	return nil
}

func (s *Server) Start() {
	fmt.Printf("[Start]Server Listener at IP %s,Port %d is starting!\n", s.IP, s.Port)
	fmt.Printf("[Zinx] Version: %s,MaxConn: %d, MaxPacketSize: %d\n", utils.GlobalObject.Version, utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPacketSize)

	go func() {

		//启动worker工作池
		s.msgHandler.StartWorkerPool()
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			log.Println("resolve tcp addr err: ", err)
			return
		}
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			log.Println("listen ", s.IPVersion, "has error :", err)
			return
		}
		log.Println("start ZinxServer ", s.Name, " successful,now listening!")
		//TODO server.go 应该有一个自动生成ID的方法
		var cid uint32
		cid = 0
		for {
			conn, err := listener.AcceptTCP()
			if err != nil {
				log.Println("Acceppt error ", err)
				continue
			}
			//3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接，那么则关闭此新的连接
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn{
				conn.Close()
				continue
			}
			//3.3 TODO Server.Start() 处理该新连接请求的 业务 方法， 此时应该有 handler 和 conn是绑定的
			dealConn := NewConnection(s,conn, cid, s.msgHandler)
			cid++
			go dealConn.Start()
		}
	}()
}

func (s *Server) Stop() {
	fmt.Println("[STOP] Zinx server, name: ", s.Name)
	//TODO  Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
	s.ConnMgr.ClearConn()
}

func (s *Server) Serve() {
	s.Start()
	//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加

	//阻塞，防止main退出
	for {
		time.Sleep(10 * time.Second)
	}
}

//路由功能，给当前服务注册一个路由业务方法，供客户端连接处理使用
func (s *Server) AddRouter(msgID uint32, router ziface.IRouter) {
	s.msgHandler.AddRouter(msgID, router)
}

func (s *Server) GetConnMgr() ziface.IConnManager {
	return s.ConnMgr
}

func (s *Server) SetOnConnectStart(hookFunc func(connection ziface.IConnection))  {
	s.OnConnStart = hookFunc
}

func (s *Server) SetOnConnectStop(hookFunc func(connection ziface.IConnection))  {
	s.OnConnStop = hookFunc
}

func (s *Server)CallOnConnectStart(conn ziface.IConnection)  {
	if s.OnConnStart != nil {
		log.Println("---> CallOnConnectStart......<---")
		s.OnConnStart(conn)
	}
}

func (s *Server) CallOnConnectStop(conn ziface.IConnection)  {
	if s.OnConnStop != nil {
		log.Println("---> CallOnConnectStop......<---")
		s.OnConnStop(conn)
	}
}
/*
创建服务器句柄
*/
func NewServer(name string) ziface.IServer {
	//先初始化全局配置文件
	utils.GlobalObject.Reload()
	return &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4",
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.TcpPort,
		msgHandler: NewMsgHandle(),
		ConnMgr:    NewConnManager(),
	}
}
